package me.youline.dataServer.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import me.youline.dataServer.ConfigConstants;
import me.youline.dataServer.controller.dto.UserAuthenticationPostDTO;
import me.youline.dataServer.controller.dto.UserAuthenticationTokenDTO;
import me.youline.dataServer.controller.dto.UserInfoFrontDTO;
import me.youline.dataServer.entity.UserBaseInfo;
import me.youline.dataServer.entity.UserSocialConnect.ConnectType;
import me.youline.dataServer.entity.UserToken;
import me.youline.dataServer.exception.DuplicatedSocialAccountBindException;
import me.youline.dataServer.exception.InvalidFileFormatException;
import me.youline.dataServer.exception.SmsVerificationCodeSendException;
import me.youline.dataServer.exception.SmsVerificationCodeSendLimitedException;
import me.youline.dataServer.exception.UnAuthenticatedUserInfoException;
import me.youline.dataServer.exception.UnExistDataException;
import me.youline.dataServer.exception.UserAccoutExistException;
import me.youline.dataServer.service.account.UserAccountRegisterService;
import me.youline.dataServer.service.account.UserAccountService;
import me.youline.dataServer.service.account.UserProfileOperationInfo.UserProfileAddInfo;
import me.youline.dataServer.service.account.UserProfileOperationInfo.UserProfileGeneralAddInfo;
import me.youline.dataServer.service.account.UserProfileOperationInfo.UserProfileSocialAddInfo;
import me.youline.dataServer.service.authentication.UserTokenService;
import me.youline.dataServer.service.front.UserAccountInfoControllerHelper;
import me.youline.dataServer.service.front.UserInfoDTOAdapter;
import me.youline.dataServer.service.support.MsgBuilder;
import me.youline.dataServer.service.support.sms.CompositeSmsVerificationService;
import me.youline.dataServer.utils.ResponseTypeOutputUtils;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartRequest;

/**
 * 用户身份认证信息控制器，负责用户登陆与用户注册
 * 
 * @author linhan
 *
 */
@RestController
@RequestMapping("/")
public class UserInfoAuthenticationController {

	@Autowired
	private UserTokenService userTokenService;

	@Autowired
	private UserAccountService userAccountService;

	@Autowired
	private UserAccountRegisterService registerService;

	@Autowired
	private CompositeSmsVerificationService verificationService;

	@Autowired
	private UserInfoDTOAdapter userInfoDTOAdapter;

	@Autowired
	private UserAccountInfoControllerHelper helper;

	private Logger logger = LoggerFactory
			.getLogger(UserInfoAuthenticationController.class);

	/**
	 * 用户普通登陆
	 * 
	 * @param tokenDTO
	 * @param response
	 */
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public void login(@Valid UserAuthenticationTokenDTO tokenDTO,
			BindingResult result, HttpServletRequest request,
			HttpServletResponse response) {
		try {
			try {
				if (result.hasErrors()) {
					response.setStatus(HttpServletResponse.SC_FORBIDDEN);
					String res = MsgBuilder.error().errorCode("200102")
							.errorMsg("用户名或密码错误，登陆失败")
							.reqUrl(request.getRequestURI()).toJSONString();
					ResponseTypeOutputUtils.renderJson(response, res);
					return;
				}
				UserToken userToken = userAccountService
						.loginUserAccount(tokenDTO);
				UserBaseInfo baseInfo = userAccountService
						.getUserBaseInfoByToken(userToken.getToken());
				response.setStatus(HttpServletResponse.SC_OK);
				logger.debug(
						"[user_login] user login publish token:{} ,userId:{} ",
						userToken.getToken(), userToken.getUserId());
				ResponseTypeOutputUtils.renderJson(
						response,
						MsgBuilder
								.success()
								.addObj("userToken", userToken)
								.addObj("userInfo",
										userInfoDTOAdapter
												.getUserBaseInfoDTO(baseInfo))
								.toJSONString());
				return;
			} catch (AuthenticationException e) {
				response.setStatus(HttpServletResponse.SC_FORBIDDEN);
				String res = MsgBuilder.error().errorCode("200102")
						.errorMsg("用户名或密码错误，登陆失败")
						.reqUrl(request.getRequestURI()).toJSONString();
				ResponseTypeOutputUtils.renderJson(response, res);
				return;
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			ResponseTypeOutputUtils.renderJson(
					response,
					MsgBuilder.error().errorCode("100001")
							.errorMsg("用户登陆业务执行失败")
							.reqUrl(request.getRequestURI()).toJSONString());
		}
	}

	/**
	 * 用户第三方账户登录
	 * 
	 * @param socialId
	 *            社交账号ID
	 * @param connectType
	 *            社交平台类别
	 * @param req
	 * @param response
	 */
	@RequestMapping(value = "/login/social", method = RequestMethod.POST)
	public void loginForThirdParty(@RequestParam String socialId,
			@RequestParam Integer connectType, HttpServletRequest req,
			HttpServletResponse response) {
		try {
			if(!isValidSocialConnectInfo(connectType, socialId)){
				response.setStatus(HttpServletResponse.SC_FORBIDDEN);
				ResponseTypeOutputUtils.renderJson(response, MsgBuilder.error()
						.errorCode("200110").errorMsg("非法的数据").toJSONString());
				return;
			}
			UserToken userToken = userAccountService
					.loginUserAccountForThirdParty(socialId,
							ConnectType.values()[connectType]);
			UserBaseInfo baseInfo = userAccountService
					.getUserBaseInfo(userToken.getUserId());
			ResponseTypeOutputUtils.renderJson(
					response,
					MsgBuilder
							.success()
							.addObj("userToken", userToken)
							.addObj("userInfo",
									userInfoDTOAdapter
											.getUserBaseInfoDTO(baseInfo))
							.toJSONString());
			return;
		} catch (UnAuthenticatedUserInfoException e) {
			response.setStatus(HttpServletResponse.SC_FORBIDDEN);
			ResponseTypeOutputUtils.renderJson(
					response,
					MsgBuilder.error().errorCode("200112")
							.errorMsg("第三方账号未绑定,登陆失败")
							.reqUrl(req.getRequestURI()).toJSONString());
		} catch (Exception e) {
			logger.error("第三方登陆业务失败:" + e.getMessage(), e);
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			ResponseTypeOutputUtils.renderJson(response, MsgBuilder.error()
					.errorCode("100001").errorMsg("第三方账号登陆业务执行失败")
					.toJSONString());
		}
	}

	/**
	 * 注册用户账户
	 * 
	 * @param userInfoDTO
	 * @param tokenDTO
	 */
	@RequestMapping(value = "/join", method = RequestMethod.POST)
	public void registerUserAccount(@Valid UserAuthenticationPostDTO tokenDTO,BindingResult result,
			@Valid UserInfoFrontDTO userInfoDTO,BindingResult frontInfoResult,  MultipartRequest fileRequest,
			HttpServletRequest request,
			HttpServletResponse response) {
		try {
			if (result.hasErrors() || frontInfoResult.hasErrors() || !this.isValidSocialConnectInfo(tokenDTO)) {
				response.setStatus(HttpServletResponse.SC_FORBIDDEN);
				ResponseTypeOutputUtils.renderJson(response, MsgBuilder.error()
						.errorCode("200110").errorMsg("非法的数据").toJSONString());
				return;
			}
			if (!verificationService.isValidCode(tokenDTO.getCode(),tokenDTO.getZone(), tokenDTO.getUserName())) {
				response.setStatus(HttpServletResponse.SC_FORBIDDEN);
				ResponseTypeOutputUtils
				.renderJson(response,
						MsgBuilder.error().errorCode("200103")
						.errorMsg("手机验证码错误").toJSONString());
				return;
			 }
			UserProfileAddInfo addInfo = null;
			try {
				if (tokenDTO.isSelfPlatformRegisterType()) {
					addInfo = new UserProfileGeneralAddInfo(
							tokenDTO.getUserName(), tokenDTO.getPassword(),
							userInfoDTOAdapter.getUserBaseInfo(userInfoDTO),
							helper.getValidUploadAvatar(fileRequest));
				} else {
					addInfo = new UserProfileSocialAddInfo(
							tokenDTO.getUserName(), tokenDTO.getPassword(),
							userInfoDTOAdapter.getUserBaseInfo(userInfoDTO),
							helper.getValidUploadAvatar(fileRequest),
							tokenDTO.getSocialId(),
							ConnectType.values()[tokenDTO.getConnectType()]);
				}

			} catch (InvalidFileFormatException e) {
				response.setStatus(HttpServletResponse.SC_FORBIDDEN);
				ResponseTypeOutputUtils
						.renderJson(
								response,
								MsgBuilder.error().errorCode("100002")
										.errorMsg("文件类型不符合要求")
										.reqUrl(request.getRequestURI())
										.toJSONString());
				return;
			}
			UserToken t = registerService.registerUserProfile(addInfo);
			UserBaseInfo baseInfo = userAccountService.getUserBaseInfo(t
					.getUserId());
			response.setStatus(HttpServletResponse.SC_CREATED);
			ResponseTypeOutputUtils.renderJson(
					response,
					MsgBuilder
							.success()
							.addObj("userToken", t)
							.addObj("userInfo",
									userInfoDTOAdapter
											.getUserBaseInfoDTO(baseInfo))
							.toJSONString());
			return;
		} catch (UserAccoutExistException m) {
			response.setStatus(HttpServletResponse.SC_FORBIDDEN);
			String msg = MsgBuilder.error().errorCode("200105")
					.errorMsg("手机号已经注册").reqUrl(request.getRequestURI())
					.toJSONString();
			ResponseTypeOutputUtils.renderJson(response, msg);
		}catch(DuplicatedSocialAccountBindException e){
			response.setStatus(HttpServletResponse.SC_FORBIDDEN);
			String msg = MsgBuilder.error().errorCode("200112")
					.errorMsg("社交账号已经绑定").reqUrl(request.getRequestURI())
					.toJSONString();
			ResponseTypeOutputUtils.renderJson(response, msg);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			ResponseTypeOutputUtils.renderJson(
					response,
					MsgBuilder.error().errorCode("100001")
							.errorMsg("用户注册业务执行失败")
							.reqUrl(request.getRequestURI()).toJSONString());
		}
	}

	/**
	 * 修改密码
	 * 
	 * @param tokenDTO
	 * @param request
	 * @param response
	 */
	@RequestMapping(value = "/reset", method = RequestMethod.POST)
	public void changePassword(@Valid UserAuthenticationPostDTO tokenDTO,
			BindingResult result, HttpServletRequest request,
			HttpServletResponse response) {
		try {
			if (result.hasErrors()) {
				response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
				ResponseTypeOutputUtils.renderJson(response, MsgBuilder.error()
						.errorCode("200110").errorMsg("非法的数据").toJSONString());
				return;
			}
			if (!verificationService.isValidCode(tokenDTO.getCode(),
					tokenDTO.getZone(), tokenDTO.getUserName())) {
				response.setStatus(HttpServletResponse.SC_FORBIDDEN);
				ResponseTypeOutputUtils
						.renderJson(response,
								MsgBuilder.error().errorCode("200103")
										.errorMsg("手机验证码错误").toJSONString());
				return;
			}
			userAccountService.changePassword(tokenDTO.getUserName(),
					tokenDTO.getPassword());
			response.setStatus(HttpServletResponse.SC_OK);
			ResponseTypeOutputUtils.renderJson(response, MsgBuilder.success()
					.toJSONString());
		} catch (UnExistDataException e) {
			response.setStatus(HttpServletResponse.SC_FORBIDDEN);
			ResponseTypeOutputUtils.renderJson(response, MsgBuilder.error()
					.errorCode("200108").errorMsg("当前用户不存在"));
			return;
		} catch (Exception e) {
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			ResponseTypeOutputUtils.renderJson(response, MsgBuilder.error()
					.errorCode("100001").errorMsg("修改密码业务执行异常"));
			return;
		}
	}

	/**
	 * 注销用户登入
	 * 
	 * @param userTokenStr
	 * @param request
	 * @param response
	 */
	@RequestMapping(value = "/logout", method = RequestMethod.DELETE)
	public void logout(
			@RequestParam(value = ConfigConstants.REQ_PARAM_APP_TOKEN_NAME) String userTokenStr,
			HttpServletRequest request, HttpServletResponse response) {
		try {
			userAccountService.logoutUserAccount(userTokenStr);
			ResponseTypeOutputUtils.renderJson(response, MsgBuilder.success()
					.toJSONString());
		} catch (UnAuthenticatedUserInfoException m) {
			response.setStatus(HttpServletResponse.SC_FORBIDDEN);
			ResponseTypeOutputUtils.renderJson(
					response,
					MsgBuilder.error().errorCode("200101")
							.errorMsg("用户账户未经认证，服务器拒绝访问")
							.reqUrl(request.getRequestURI()).toJSONString());

		} catch (Exception e) {
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			ResponseTypeOutputUtils.renderJson(response,
					MsgBuilder.error().errorCode("100001").errorMsg("注销业务执行失败")
							.reqUrl(request.getRequestURI()).toJSONString());
		}
	}
	
	@RequestMapping(value = "/verificationCode", method = RequestMethod.GET)
	public void sendVerificationCode(@RequestParam String phoneNum,HttpServletRequest request, HttpServletResponse response){
		try {
			verificationService.sendCode(phoneNum);
			response.setStatus(HttpServletResponse.SC_OK);
			ResponseTypeOutputUtils.renderJson(response,
					MsgBuilder.success().toJSONString());
			return;
		} catch (SmsVerificationCodeSendException e) {
			if(e instanceof SmsVerificationCodeSendLimitedException){
				response.setStatus(HttpServletResponse.SC_FORBIDDEN);
				ResponseTypeOutputUtils.renderJson(response,
						MsgBuilder.error().errorCode("200114").errorMsg("当前手机号接收短信验证码条数达到上限")
								.reqUrl(request.getRequestURI()).toJSONString());
				return;
			}
			response.setStatus(HttpServletResponse.SC_NOT_FOUND);
			ResponseTypeOutputUtils.renderJson(response,
					MsgBuilder.error().errorCode("200113").errorMsg("验证码发送失败，请重新再试")
							.reqUrl(request.getRequestURI()).toJSONString());
		} catch(Exception e){
			logger.error(e.getMessage(),e);
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			ResponseTypeOutputUtils.renderJson(response,
					MsgBuilder.error().errorCode("100001").errorMsg("请求发送验证码执行失败")
							.reqUrl(request.getRequestURI()).toJSONString());
		}
	}
	
	/**
	 * 是否是有效第三方账户连接信息
	 * @param dto
	 * @return
	 */
	private boolean isValidSocialConnectInfo(UserAuthenticationPostDTO dto){
		if(!dto.isSelfPlatformRegisterType() && StringUtils.isBlank(dto.getSocialId())){//第三方平台的请求，必须带上第三方ID
			return false;
		}
		if(dto.getConnectType() >= ConnectType.values().length){//第三方平台类型标号不能超过平台定义的最大值
			return false;
		}
		return true;
	}
	
	/**
	 * 是否是有效第三方账户连接信息
	 * @param socialConnectType
	 * @param socialId
	 * @return
	 */
	private boolean isValidSocialConnectInfo(int socialConnectType, String socialId){
		 if(socialConnectType <0 || socialConnectType >= ConnectType.values().length || StringUtils.isBlank(socialId)){
			 return false;
		 }
		 return true;
	}

}
